﻿// Copyright (c) Microsoft. All rights reserved.

using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Microsoft.Agents.AI.Hosting.OpenAI.ChatCompletions.Models;

/// <summary>
/// Represents a choice in a chat completion response.
/// </summary>
internal sealed record ChatCompletionChoice
{
    /// <summary>
    /// The index of the choice in the list of choices.
    /// </summary>
    [JsonPropertyName("index")]
    public required int Index { get; init; }

    /// <summary>
    /// The reason the model stopped generating tokens.
    /// This will be stop if the model hit a natural stop point or a provided stop sequence, length if the maximum number of tokens specified in the request was reached,
    /// content_filter if content was omitted due to a flag from our content filters, tool_calls if the model called a tool,
    /// or function_call (deprecated) if the model called a function.
    /// </summary>
    [JsonPropertyName("finish_reason")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? FinishReason { get; init; }

    /// <summary>
    /// A chat completion message generated by the model.
    /// </summary>
    [JsonPropertyName("message")]
    public required ChoiceMessage Message { get; init; }
}

/// <summary>
/// A chat completion message generated by the model.
/// </summary>
internal sealed record ChoiceMessage
{
    /// <summary>
    /// The role of the author of this message.
    /// </summary>
    [JsonPropertyName("role")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Role { get; set; }

    /// <summary>
    /// A list of annotations for this message. Currently used for web search citations.
    /// </summary>
    [JsonPropertyName("annotations")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public IList<ChoiceMessageAnnotation>? Annotations { get; set; }

    /// <summary>
    /// The contents of the message.
    /// </summary>
    [JsonPropertyName("content")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Content { get; set; }

    /// <summary>
    /// The refusal message generated by the model.
    /// </summary>
    [JsonPropertyName("refusal")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Refusal { get; set; }

    /// <summary>
    /// If the audio output modality is requested, this object contains data about the audio response from the model.
    /// </summary>
    [JsonPropertyName("audio")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public ChoiceMessageAudio? Audio { get; set; }

    /// <summary>
    /// Deprecated and replaced by tool_calls. The name and arguments of a function that should be called, as generated by the model.
    /// </summary>
    [JsonPropertyName("function_call")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public ChoiceMessageFunctionCall? FunctionCall { get; set; }

    /// <summary>
    /// The tool calls generated by the model, such as function calls.
    /// </summary>
    [JsonPropertyName("tool_calls")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public IList<ChoiceMessageToolCall>? ToolCalls { get; set; }
}

/// <summary>
/// Audio output data in a chat completion message.
/// </summary>
internal sealed record ChoiceMessageAudio
{
    /// <summary>
    /// Base64 encoded audio bytes generated by the model, in the format specified in the request.
    /// </summary>
    [JsonPropertyName("data")]
    public string? Data { get; init; }

    /// <summary>
    /// The Unix timestamp (in seconds) for when this audio response will no longer be accessible on the server for use in multi-turn conversations.
    /// </summary>
    [JsonPropertyName("expires_at")]
    public int ExpiresAt { get; init; }

    /// <summary>
    /// Unique identifier for this audio response.
    /// </summary>
    [JsonPropertyName("id")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Id { get; init; }

    /// <summary>
    /// Transcript of the audio generated by the model.
    /// </summary>
    [JsonPropertyName("transcript")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Transcript { get; init; }
}

/// <summary>
/// Deprecated. The name and arguments of a function that should be called, as generated by the model.
/// </summary>
internal sealed record ChoiceMessageFunctionCall
{
    /// <summary>
    /// The name of the function to call.
    /// </summary>
    [JsonPropertyName("name")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Name { get; init; }

    /// <summary>
    /// The arguments to call the function with, as generated by the model in JSON format.
    /// Note that the model does not always generate valid JSON, and may hallucinate parameters not defined by your function schema.
    /// Validate the arguments in your code before calling your function.
    /// </summary>
    [JsonPropertyName("arguments")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Arguments { get; init; }
}

/// <summary>
/// Represents a tool call generated by the model.
/// </summary>
internal sealed record ChoiceMessageToolCall
{
    /// <summary>
    /// The ID of the tool call.
    /// </summary>
    [JsonPropertyName("id")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? Id { get; init; }

    /// <summary>
    /// The type of the tool.
    /// </summary>
    public string Type => "function";

    /// <summary>
    /// The function that the model called.
    /// </summary>
    [JsonPropertyName("function")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public ChoiceMessageFunctionCall? Function { get; set; }
}

/// <summary>
/// An annotation for a message, used for web search citations.
/// </summary>
internal sealed record ChoiceMessageAnnotation
{
    /// <summary>
    /// The type of annotation. Always 'url_citation' for web search results.
    /// </summary>
    [JsonPropertyName("type")]
    public string Type => "url_citation";

    /// <summary>
    /// The URL citation details.
    /// </summary>
    [JsonPropertyName("url_citation")]
    public required AnnotationUrlCitation AnnotationUrlCitation { get; init; }
}

/// <summary>
/// A citation to a URL for a web search result.
/// </summary>
internal sealed record AnnotationUrlCitation
{
    /// <summary>
    /// The character index in the message content where the citation ends.
    /// </summary>
    [JsonPropertyName("end_index")]
    public int? EndIndex { get; init; }

    /// <summary>
    /// The character index in the message content where the citation starts.
    /// </summary>
    [JsonPropertyName("start_index")]
    public int? StartIndex { get; init; }

    /// <summary>
    /// The title of the cited resource.
    /// </summary>
    [JsonPropertyName("title")]
    public string? Title { get; set; }

    /// <summary>
    /// The URL of the cited resource.
    /// </summary>
    [JsonPropertyName("url")]
    public string? Url { get; set; }
}
